import threading

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
import pandas as pd
from dash.dependencies import Input, Output


class DashServer(threading.Thread):
    def __init__(self, update_interval=-1, rolling_mean=1, update_func=None):
        threading.Thread.__init__(self)
        self.running = False
        self.rolling_mean = int(rolling_mean)
        self.update_interval = int(update_interval)
        self.data = pd.Series(dtype=int)
        self.fig = go.Figure(data=[go.Scatter(x=[], y=[])])
        self.app = dash.Dash()

        self.app.layout = html.Div([
            html.H4('Dvr Monitor'),
            html.Div(id='live-update-text'),
            html.Button('Start', id='button_start'),
            dcc.Graph(figure=self.fig, id='live-update-graph'),
            dcc.Interval(
                id='interval-component',
                interval=self.update_interval,  # in milliseconds
                n_intervals=0
            )
        ])
        self.update_func = update_func

        @self.app.callback([Output('button_start', 'children'), Output('interval-component', 'disabled')],
                           [Input('button_start', 'n_clicks')])
        def on_button_clicked(n_clicks):
            if not n_clicks:
                return 'RESUME', False
            return ('RESUME', False) if int(n_clicks % 2) == 0 else ('PAUSE', True)

        @self.app.callback(Output('live-update-text', 'children'),
                           [Input('interval-component', 'n_intervals')])
        def update_metrics(n):
            style = {'padding': '5px', 'fontSize': '16px'}
            return [
                html.Span('Monitor running for {0:.2f} ms.'.format(self.update_interval * n), style=style),
            ]

        @self.app.callback(Output('live-update-graph', 'figure'),
                           [Input('interval-component', 'n_intervals')])
        def update_graph_live(n):
            avg = self.data.rolling(window=self.rolling_mean, min_periods=1).mean()
            self.fig.data[0].x = avg.index
            self.fig.data[0].y = avg.values
            return self.fig

    def start(self):
        self.running = True
        threading.Thread.start(self)
        self.app.run_server(debug=True, use_reloader=False)

    def run(self):
        print('Dash server started')
        while self.running:
            item = self.update_func(self)
            if item:
                self.data = self.data.append(pd.Series(item), ignore_index=True)
        print('Dash server stopped')

    def stop(self):
        self.running = False
        threading.Thread.join(self)
